# Copyright (c) 2025 pony working team
# SPDX-License-Identifier: MulanPSL-2.0

# reference to:
# 	https://www.gnu.org/software/make/manual/make.html
# 	https://blog.csdn.net/canpool/article/details/124334329

# global variables
VPATH           = $(root_dir)
MAGIC           = $(root_dir)/scripts/make/magic.mk

outdir         ?= out

# extracts CURDIR name but the directory-part
target          = $(notdir $(CURDIR))

# default values for VERBOSE, LIST, DEBUG
V              ?= 0
L              ?= 0
D              ?= 0

# variables used for iterate sub dirs must be defined as ':='
# parse from $(root_dir)
subs           := $(abspath $(root_dir))
curdir         :=
proj           := $(abspath ./)

# all dir (not abspath) being built will be added to dirs
dirs           :=

lflags         :=

cflags-global  :=
inc-global     := -I$(proj)/config

arch            = $(patsubst "%",%,$(CONFIG_ARCH))
soc             = $(curdir)/$(patsubst "%",%,$(CONFIG_SOC))

include        config/kconfig.mk
include        $(root_dir)/scripts/make/arch/$(arch)/def.mk
include        $(root_dir)/scripts/make/common.mk
include        $(MAGIC)

cflags-global  += $(cflags-arch)

################################################################################
# tool gcc rules
################################################################################

# src-$(dir) holds the filename with absolutely path
ifdef CONFIG_USER_APP
srcs           := $(patsubst $(root_dir)%,$(outdir)%,$(foreach d,$(dirs),$(usr-$(d))))
else
srcs           := $(patsubst $(root_dir)%,$(outdir)%,$(foreach d,$(dirs),$(src-$(d))))
endif
# supports building projects that are not in the pony directory
srcs           := $(patsubst $(proj)%,$(outdir)%,$(srcs))

objs           := $(srcs:.c=.o)
objs           := $(objs:.s=.o)
objs           := $(objs:.S=.o)
objs           := $(objs:.cpp=.o)

outdirs        := $(sort $(dir $(objs)))

# for xbuild
XB_COUNTER := 0
XB_FILES := $(words $(objs))

define xbuild
    $(eval XB_COUNTER := $(shell echo $$(($(XB_COUNTER)+1))))
    @echo "[$(XB_COUNTER)/$(XB_FILES)] Building $<"
    @$(1) || (echo "Failed: $(1)" && false)
endef
# end of xbuild

ifeq ($(V),1)
    $(foreach v, $(sort $(filter src-% inc-% par-% cflags-%, $(.VARIABLES))), $(info $(v) = $($(v))))
    $(info objects = $(objs))
    $(info outdir = $(strip $(outdir)))
    $(info outdirs = $(outdirs))
endif

ifeq ($(CX),)
    CX          = $(CC)
endif

.PHONY : all
all : $(outdir)/$(target).bin $(outdir)/$(target).hex

$(outdir)/$(target).hex : $(outdir)/$(target).elf
	$(OBJCOPY) $< $@ -O ihex

$(outdir)/$(target).bin : $(outdir)/$(target).elf
	$(OBJCOPY) $< $@ -O binary

$(outdir)/$(target).elf : $(objs) $(ld_script)
	$(CX) $(filter %.o, $^) $(cflags-arch) $(lflags) -o $@
	$(SIZE) $@

$(outdir)/%.o : %.c
	$(call xbuild,$(strip $(CC) $(cflags-common) $(cflags-global) $(cflags-$(abspath $<)) -I$(proj) $(inc-global) $(inc-$(abspath $<)) $< -c -o $@))

$(outdir)/%.o : %.s
	$(call xbuild,$(strip $(CC) $(cflags-common) $(cflags-global) $(cflags-$(abspath $<)) -I$(proj) $(inc-global) $(inc-$(abspath $<)) $< -c -o $@))

$(outdir)/%.o : %.S
	$(call xbuild,$(strip $(CC) $(cflags-common) $(cflags-global) $(cflags-$(abspath $<)) -I$(proj) $(inc-global) $(inc-$(abspath $<)) $< -c -o $@))

$(outdir)/%.o : %.cpp
	$(call xbuild,$(strip $(CPP) $(cppflags-common) $(cflags-global) $(cflags-$(abspath $<)) -I$(proj) $(inc-global) $(inc-$(abspath $<)) $< -c -o $@))

.PHONY : clean
clean : cleantest
	@rm -rf $(objs) $(objs:.o=.d) $(objs:.o=.list)

menuconfig:
ifeq ($(OS),Windows_NT)
	@winpty python3 $(root_dir)/scripts/prj.py -m
else
	@python3 $(root_dir)/scripts/prj.py -m
endif

# define rules for creating out dirs
define dir-rule
    ifeq ($(V),1)
        $$(info define rule for $(1))
    endif
    $(1) :
	@mkdir -p $(1)
endef

$(foreach d,$(outdirs),$(eval $(call dir-rule,$(d))))

# define depend rules for objs to dirs
define obj-rule
    ifeq ($(V),1)
        $$(info define rule for $(1) : $$(dir $(1)))
    endif
    $(1) : | $$(dir $(1))
endef

$(foreach o,$(objs),$(eval $(call obj-rule,$(o))))

-include $(objs:.o=.d)

include $(root_dir)/scripts/make/test.mk

ifdef GENIDE

################################################################################
# other IDE, like keil
################################################################################

ini             = .flags.ini

ide             = $(patsubst "%",%,$(CONFIG_IDE_NAME))

# src-$(dir) or usr-$(dir) holds the filename with absolutely path

ifdef CONFIG_USER_APP
dir-prefix = usr
else
dir-prefix = src
endif

$(ini) :
	$(file >  $@,[global])
	$(file >> $@,flags = $(strip $(filter -D%, $(cflags-common) $(cflags-global))))
	$(file >> $@,inc   = $(strip $(inc-global)))
	$(foreach f, $(foreach d,$(dirs),$($(dir-prefix)-$(d))),    \
                     $(file >>$@,[$(f)])                            \
                     $(file >>$@,flags = $(strip $(cflags-$(f))))   \
                     $(file >>$@,inc   = $(strip $(filter-out $(inc-global), $(inc-$(abspath $(f)))))))

.PHONY : gen-ide
gen-ide: $(ini)
	@python3 $(root_dir)/scripts/gen_ide_$(ide).py $<

endif

syscall_stub.c :
	@python3 $(root_dir)/scripts/make/arch/$(arch)/gen_syscalls.py $(root_dir)/service/src/syscall.def
